#include <cv.h>
#include <cxcore.h>
#include <math.h>
using namespace std;

struct Rectangle
{
	int x;
	int y;
	int width;
	int height;
};

__declspec(dllexport) int DetectCells(IplImage* binaryInputImage, IplImage* contourImage, int &left, int &top, int &rectWidth, int &rectHeight, int &n, Rectangle* boundRectList)
{
	IplImage* tempEdgeImage = cvCreateImage(cvSize(binaryInputImage->width, binaryInputImage->height), binaryInputImage->depth, binaryInputImage->nChannels);
	cvCopyImage(binaryInputImage, tempEdgeImage);

	// remove "1mm" label of sperm image
	double maxWidth = binaryInputImage->width * 0.84;
	double maxHeight = binaryInputImage->height * 0.95;
	int area;
	int width,height;
	double minarea;
	CvRect biggestRect = cvRect(0, 0, 1, 1);
	// min area to remove noises
	minarea = 10 * 10;
	
	CvMemStorage* storage = cvCreateMemStorage(0);
	CvSeq* contour;
	CvChainPtReader reader;
	int num = 0;

	// extract contour
	cvFindContours(tempEdgeImage, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_CODE);

	// extract each connected component
	for( ; contour != 0; contour = contour->h_next )
	{
		// identify bound rectangle
		int r = 0, b = 0;
		int l = tempEdgeImage->width;
		int t = tempEdgeImage->height;
		cvStartReadChainPoints((CvChain*)contour, &reader);
		
		for (int i = 0; i<contour->total; i++)
		{
			CvPoint edge = cvReadChainPoint(&reader);
			l = min(l, edge.x);
			t = min(t, edge.y);
			r = max(r, edge.x);
			b = max(b, edge.y);
		}		
		if (r > l && b > t)
		{			
			if (l <= maxWidth || t <= maxHeight)
			{
				width = abs(r-l);
				height = abs(b-t);
				//
				if (width >= 15 || height >= 15)
				{
					if ((width * height * 1.0) >= minarea)
					{
						area = biggestRect.height * biggestRect.width;
						if ((width * height) >= area)
						{
							biggestRect = cvRect(l,t,width,height);
						}
						boundRectList[num].x = l;
						boundRectList[num].y = t;
						boundRectList[num].width = width;
						boundRectList[num].height = height;

						cvDrawRect(contourImage, cvPoint(l,t), cvPoint(r,b), cvScalar(255,0,0), 1, 8, 0);
						cvDrawContours(contourImage, contour, cvScalar(0,0,255), cvScalar(0,0,0), 0, 1);
						num++;
					}
				}
			}
		}
	}
	left = biggestRect.x;
	top = biggestRect.y;
	rectWidth = biggestRect.width;
	rectHeight = biggestRect.height;
	n = num;
	return num;
}
__declspec(dllexport) void SplitCells(IplImage* input, IplImage* result, int block_size = 9, double threshold = 0.7, int boundary_size = 3)
{
	//IplImage* result = cvCreateImage(cvSize(input->width, input->height), input->depth, input->nChannels);
	cvCopyImage(input, result);
	int width = input->width;
	int height = input->height;
	int block_width = (int)floor(width * 1.0 / block_size)-2;
	int block_height = (int)floor(height * 1.0 / block_size)-2;
	int i, j, block_i, block_j, min_i, min_j, max_i, max_j;
	int block_density = (int)floor(threshold * block_size * block_size);
	uchar* srcData = (uchar *)input->imageData;
	uchar* dstData = (uchar *)result->imageData;
	int step = input->widthStep/sizeof(uchar);
	
	int sum;
	
	for(block_i = 0; block_i < block_height; block_i++)
	{
		for(block_j = 0; block_j < block_width; block_j++)
		{
			sum = 0;
			// calculate the density of this block
			for(i = block_i * block_size; i < (block_i + 1) * block_size; i++)
			{
				for(j = block_j * block_size; j < (block_j + 1) * block_size; j++)
				{
					sum += (srcData[i * step + j] == 255 ? 1 : 0);
				}
			}
			if (sum <= block_density && sum > 0)
			{
				// calculate core_size
				min_i = block_i * block_size + boundary_size;
				min_j = block_j * block_size + boundary_size;
				max_i = (block_i + 1) * block_size - boundary_size;
				max_j = (block_j + 1) * block_size - boundary_size;
				// remove boundary
				for(i = block_i * block_size; i < (block_i + 1) * block_size; i++)
				{
					for(j = block_j * block_size; j < (block_j + 1) * block_size; j++)
					{
						if (i < min_i || i > max_i || j < min_j || j > max_j)
						{
							dstData[i * step + j] = (uchar)0;
						}
					}
				}
			}

		}
	}
}
__declspec(dllexport) int CoutingPixelValue(IplImage* src, int grayValue = 255)
{
	int valueSum = 0;
	

	int width = src->width;
	int height = src->height;

	int i, j;
	uchar* srcData = (uchar *)src->imageData;
	int step = src->widthStep/sizeof(uchar);

	for(j = 0; j < width; j++) 
	{ 
		for(i = 0; i < height; i++) 
		{ 
			if ((int)srcData[i * step + j] == grayValue)
				valueSum++;
		}	
	}
	return valueSum;
}